/*
 * Copyright (C) 2012 by Hao Hou<ghost89413@gmail.com>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>*
 */

/*
 * This file is one part of Vine, the lightweight input mehtod platform
 * Definitions for Input Method Development
 * IM for Vine Platform is dynamic linked, that means you does not 
 * have to link any additional library in your program.  
 * Use the marocs defined in this file, compiler will generate all
 * symbols Vine Platform needed. 
 * The only thing you should do, is to write a MetaData section to
 * tell Vine Platform how to use your IM. 
 * In addition, the Vine Platform will tell the IM how to use the
 * platform service. It's also wrapped by macros in this file. You
 * can make an platform call use the macros prefixed by "IM". Because
 * each IM holds an independent function table, so future version of
 * Vine can easily compate with older IM plug-ins.
 * To make the compiler produce the right binary, you should make 
 * sure that options -fPCI and -shared have been passed to compile
 * Any libraries is needed for build IME? None :-) 
 * Hope you would enjoy that.
 */ 
#ifndef __IME_H__
#define __IME_H__
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct {
	int (*Commit)(char* text,void* IC);	//commit a text to client
	char** (*GetCandidatesList)(size_t* n, void* IC);
	int (*UpdateCandidates)(char** list, int count, void* IC);  //update caidate list
	char* (*GetPrecommitText)(void* IC);
	int (*UpdatePrecommitText)(char* text, void* IC);
	int (*RegisterForwardFilter)(uint32_t sym_left, uint32_t sym_right,  //[sym_left,sym_right)
				     uint32_t mask_neg, uint32_t mask_pos, uint32_t release,
				     int (*Proc)(uint32_t, uint32_t,uint32_t ,void*),void* ic);
	int (*SwitchForwardFilter)(uint32_t filter_id, uint32_t enable, void* ic);
	int (*ResetForwardFilter)(void* ic);
	int (*SetTrayIcon)(const char* icon,void* ic);
	int (*ReadConfigure)(const char* name,uint32_t type,void* buf,void* default_value,void* IC);

	//TODO: Calls of Toolbar Window
} FrameWorkFunctions;
typedef struct {
	/* If user wants to invoke APIs in OnInitialize function,
	 * the auxiliary macro is not compitible in this function.
	 * In order to resolve this problem, the framework provide
	 * a fake IC which makes all macro works.
	 * To genreate an fake IC for an IM, you may use the macro MAKE_FAKE_IC
	 * which is defined in the file loader.h
	 */
	int (*OnInitialize)(char* param,void* fakeIC);  //called when IME Inialized
	int (*OnFinalize)();                            //called when IME Finalized
	int (*OnEnabled)(void* IC);
	int (*OnDisabled)(void* IC);
	int (*OnPreeditTextChanged)(char* text,uint32_t length,void* IC);
	//TODO: On IM Config Changed
} IMFunctions;
typedef struct {
	char* 	Name;		//name of IME
	size_t  IC_Size;	//Size of IME IC
	uint8_t APIVersion;     //Require Specified Version of APIs, reserved for future update
	size_t  NCandidates;	//Number of Max Candidate
	char	Parameter[1024]; 
	uint8_t id;
	uint8_t LoadID;
	FrameWorkFunctions framework;
	IMFunctions 	   imfunction;
} IMMetaData;


/* Following macros helps you to produce log that is in Vine style */
#define IMWriteLog(e,fmt,arg...) ({\
	static const char LevelChar[] = "FEWNITD";\
	fprintf(stderr,"%c[%s@%s:%d] "fmt"\n" ,\
		LevelChar[e],__FUNCTION__,\
		__FILE__,__LINE__,##arg);\
	})
#define IM_LOG_FATAL(fmt,arg...) IMWriteLog(0,fmt,##arg)
#define IM_LOG_ERROR(fmt,arg...) IMWriteLog(1,fmt,##arg)
#define IM_LOG_WARNING(fmt,arg...) IMWriteLog(2,fmt,##arg)
#define IM_LOG_NOTICE(fmt,arg...) IMWriteLog(3,fmt,##arg)
#define IM_LOG_INFO(fmt,arg...) IMWriteLog(4,fmt,##arg)
#define IM_LOG_TRACE(fmt,arg...) IMWriteLog(5,fmt,##arg)
#define IM_LOG_DEBUG(fmt,arg...) IMWriteLog(6,fmt,##arg)

/*Return values for Event Forward procedures*/
#define FE_SUCCEED	0	//Successfully processed
#define FE_SYSTEM	-1	//Unsuccessfully processed, forward it to Vine System
#define FE_CLIENT	-2	//Unsuccessfully processed, forward it to Client Window

/*Action selector for User Event Forward*/
#define IMKeyActionPress   0 	//Only Key Press Event
#define IMKeyActionRelease 1	//Only Key Release Event
#define IMKeyActionAny     2	//Both

/*Configure Data Type Indicators*/
#define IMConfInteger	0
#define IMConfString	1

/*State selector for UEF */
#define IMStateNone	0x0
#define IMStateShift	0x1
#define IMStateCaps	0x2
#define IMStateCtrl	0x4
#define IMStateAlt	0x8
#define IMStateNum	0x10
#define IMStateSuper	0x40
#define IMStateScroll	0x80
#define IMStateAll	0xffffffffUL

/*Syms*/
#define IMSymBackSpace	0xff08
#define IMSymTab	0xff09
#define IMSymLinefeed	0xff0a
#define IMSymClear	0xff0b
#define IMSymReturn	0xff0d
#define IMSymPause	0xff13
#define IMSymScrollLock	0xff14
#define IMSymSysReq	0xff15
#define IMSymEscape	0xff1b
#define IMSymHome	0xff50
#define IMSymLeft	0xff51
#define IMSymUp		0xff52
#define IMSymRight	0xff53
#define IMSymDown	0xff54
#define IMSymPageUp	0xff55
#define IMSymPageDown	0xff56
#define IMSymEnd	0xff57 
#define IMSymMenu	0xff67
#define IMNumLock	0xff7f
#define IMSymEqual	0xffbd
#define IMSymMultiply	0xffaa
#define IMSymAdd	0xffab
#define IMSymSeparator	0xffac
#define IMSymSubtract	0xffad
#define IMSymDecimal	0xffae
#define IMSymDivide	0xffaf
#define IMSymKeypad0	0xffb0
#define IMSymKeypad1	0xffb1
#define IMSymKeypad2	0xffb2
#define IMSymKeypad3	0xffb3
#define IMSymKeypad4	0xffb4
#define IMSymKeypad5	0xffb5
#define IMSymKeypad6	0xffb6
#define IMSymKeypad7	0xffb7
#define IMSymKeypad8	0xffb8
#define IMSymKeypad9	0xffb9
#define IMSymF1		0xffbe
#define IMSymF2		0xffbf
#define IMSymF3		0xffc0
#define IMSymF4		0xffc1
#define IMSymF5		0xffc2
#define IMSymF6		0xffc3
#define IMSymF7		0xffc4
#define IMSymF8		0xffc5
#define IMSymF9		0xffc6
#define IMSymF10	0xffc7
#define IMSymF11	0xffc8
#define IMSymF12	0xffc9
#define IMSymShiftL	0xffe1
#define IMSymShiftR	0xffe2
#define IMSymControlL	0xffe3
#define IMSymControlR	0xffe4
#define IMSymCapsLock	0xffe5
#define IMSymShiftLock	0xffe6
#define IMSymMetaL	0xffe7
#define IMSymMetaR	0xffe8
#define IMSymAltL	0xffe9
#define IMSymAltR	0xffea
#define IMSymSuperL	0xffeb
#define IMSymSuperR	0xffec
#define IMSymHyperL	0xffed
#define IMSymHyperR	0xffee
#define IMSymDelete	0xffff


/* 
 * Macros for invoking Vine Platform service
 * Commit 		: Commit a string to client window. IC is needed
 * 			  example: IMCommit("example",ic);
 * GetCandidatesList	: Get a pointer of interal storage for Candidate.
 * 			  This method is recommended, because manipulate interal
 * 			  buffer directory can make the UpdateCandidateList method
 * 			  be able to avoid memmove operation. IC is needed
 * 			  example: int 	n;
 * 			  	   char**  list = IMGetCandidatesList(&n,ic);
 * UpdateCandidateList  : Update CandidateList, this call will trigger UI updating method.IC needed
 * 			  example: char* list[] = {"cand0","cand1","cand2"};
 * 			           IMUpdateCandidates(list,3,ic);
 * GetPrecommitText	: Get a pointer of PrecommitTextBuffer. IC needed
 * 			  example: char* buf = IMGetPrecommitText(ic)
 * UpdatePrecommitText	: Update PrecommitTextBuffer, trigger UI calls. IC needed
 * 			  example: IMUpdatePrecommitText("example",ic)
 * RegisterForwardFilter: Register a User Event Foward procedure
 * 			  The UEF is a group of callbacks for key events,
 * 			  you can use this call back to specialize your IM and
 * 			  override the default action of Vine Platform.
 *			  example: int handler(uint32_t sym, uint32_t state, void* ic);
 *			  	   int id = IMRegisterEventHandler('0', '9', //apply to key ['0','9')
 *			  	   			  IMStateNone,IMStateCtrl, // CTRL_[0-9]
 *			  	   			  IMActionAny,		   //Press&Release
 *			  	   			  handler,		   //What to do
 *			  	   			  ic			   //current context
 *			  	   			  );
 * ResetForwardFilter	: Delete all UFE Filters.
 * 			  exampe: IMResetForwardFilter(ic);
 * SetTrayIcon		: Set tray icon use specified icon file
 * 			  example: IMSetTrayIcon("./icon.png",ic);
 * 
 */
#define IMGetIM(i) (***(IMMetaData***)((char*)(i) - sizeof(void*)))
#define IMCommit(str,i) (IMGetIM(i).framework.Commit(str,i))  
#define IMGetCandidatesList(n,i) (IMGetIM(i).framework.GetCandidatesList(n,i))
#define IMUpdateCandidates(l,c,i) (IMGetIM(i).framework.UpdateCandidates(l,c,i))
#define IMGetPrecommitText(i) (IMGetIM(i).framework.GetPrecommitText(i))
#define IMUpdatePrecommitText(t,i) (IMGetIM(i).framework.UpdatePrecommitText(t,i))
#define IMRegisterForwardFilter(l,r,n,p,R,g,i) (IMGetIM(i).framework.RegisterForwardFilter(l,r,n,p,R,g,i))
#define IMSwitchForwardFilter(f,e,i) (IMGetIM(i).framework.SwitchForwardFilter(f,e,i))
#define IMResetForwardFilter(i) (IMGetIM(i).framework.ResetForwardFilter(i));
#define IMSetTrayIcon(f,i) (IMGetIM(i).framework.SetTrayIcon(f,i))
#define IMReadConfigure(n,t,b,d,i) (IMGetIM(i).framework.ReadConfigure(n,t,b,d,i))
#define IMGetIMMetaData(n,i) (IMGetIM(i).n)


/* What function should the Vine Platform call first? GetMetaData */
#include <malloc.h>
#include <string.h>
#define GETMETADATA GetMetaData
#define GETMETADATASTR "GetMetaData"
/* Macros to help you to produce right code of GetMetaData */
#define MetaDataBegin(IMEName,ICType,API) \
	IMMetaData* GETMETADATA(void) {\
		static uint8_t load_id = 0;\
		IMMetaData * __ime_meta_data__ = \
			(IMMetaData*) malloc (sizeof(IMMetaData));\
		if(NULL == __ime_meta_data__) return NULL;\
		memset(__ime_meta_data__ , 0, sizeof(IMMetaData));\
		__ime_meta_data__->Name = #IMEName;\
		__ime_meta_data__->IC_Size = sizeof(ICType);\
		__ime_meta_data__->APIVersion = API;\
		__ime_meta_data__->LoadID = load_id++;
#define MetaDataEnd return(__ime_meta_data__);}
#if 0
#define MetaDataBegin(Name,ICType,API) \
	IMMetaData ime_internal_meta = {#Name,sizeof(ICType),API};\
	IMMetaData* GETMETADATA(void){
#define MetaDataEnd   return &ime_internal_meta;}
#endif
/* Following Macros have to be invoked in the MetaData Section */
/* Register an event handler */
#define IMRegisterEventHandler(name,func) __ime_meta_data__->imfunction.name = func 
#define IMSetMetaData(name,value) 	  __ime_meta_data__->name = value

#if 0
/* 
 * To allow user define the MetaData anywhere they want,
 * I have to make sure that the ime_internal_meta is decleared
 * This point should produce the declearation in front of any
 * code of user's. Ugly solution ...
 */
extern IMMetaData ime_internal_meta;
#endif
#endif 
